<template>
    <div class="gridster">
        <div class="gridster_top-head" :style="{height: barWidth + 'px'}">
            <svg :width="svgWidth + barWidth" :height="barWidth">
                <VoGridSvg :width="barWidth" :height="barWidth" >
                    <VoGridRect :strokeWidth="1" :activeStrokeWidth="1" :rx="0" :ry="0" width="100%" height="100%"></VoGridRect>
                    <VoGridText y="70%">
                        <tspan>#</tspan>
                    </VoGridText>
                </VoGridSvg>
                <template v-for="(c, x) in col">
                    <VoGridSvg :key="x" :x="x" :offsetX="barWidth" :width="gridWidth" :height="barWidth" >
                        <VoGridRect :strokeWidth="1" :activeStrokeWidth="1" :rx="0" :ry="0" width="100%" height="100%"></VoGridRect>
                        <VoGridText y="70%">
                            <tspan>{{c}}</tspan>
                        </VoGridText>
                    </VoGridSvg>
                </template>
            </svg>
        </div>
        <div class="gridster-row">
            <svg :width="barWidth" :height="svgHeight">
                <template v-for="(r, y) in row">
                    <VoGridSvg :key="y" :y="y" :width="barWidth" :height="gridHeight">
                        <VoGridRect :strokeWidth="1" :activeStrokeWidth="1" :rx="0" :ry="0" width="100%" height="100%"></VoGridRect>
                        <VoGridText>
                            <tspan>{{r}}</tspan>
                        </VoGridText>
                    </VoGridSvg>
                </template>
            </svg>
            <svg :width="svgWidth" :height="svgHeight"
                @mousedown="gridsterMousedown($event)"
                @mouseup="gridsterMouseup($event)"
                @mouseleave="gridsterMouseleave($event)"
                @mousemove="gridsterMousemove($event)">
                <defs>
                    <VoGridStop id="grid_stop"></VoGridStop>
                    <VoMoveBar id="grid_movebar"></VoMoveBar>
                </defs>
                <template v-for="(r, y) in row">
                    <template v-for="(c, x) in col">
                        <VoGridSvg :key="`svg_${y}_${x}`" 
                            ref="grid"
                            :x="x" 
                            :y="y" 
                            :width="gridWidth" 
                            :height="gridHeight"
                            :disabled="disabled"
                            :selectState="selectIng"
                            :isDrag="gridDrag"
                            @up-select="svgSelect($event)"
                            @up-over="svgUpOver($event)"
                            @up-down="svgMousedown($event)"
                            @up-drag="svgUpDrag($event)">
                            <template>
                                <VoGridRect :active="isActive(x, y)" 
                                    :enter="moveInGrid && moveInGrid.x == x && moveInGrid.y == y"
                                    stroke="#FFFFFF" 
                                    activeStroke="#FFFFFF" 
                                    width="100%" height="100%">
                                </VoGridRect>
                                <VoGridCircle :active="isActive(x, y)" y="40%" r="20%">
                                </VoGridCircle>
                                <VoGridUse href="leibieicon-xiaoshu" transformX="-10%" transformY="-10%" width="20%" height="20%" y="40%"></VoGridUse>
                                <VoGridText :active="isActive(x, y)" y="80%">
                                    <tspan>{{y}}_{{x}}</tspan>
                                    <tspan>空闲</tspan>
                                </VoGridText>
                                <use v-if="isDisabled(x, y)" href="#grid_stop"></use>
                            </template>
                        </VoGridSvg>
                    </template>
                </template>
            </svg>
        </div>
    </div>
</template>

<script>
import * as Grid from './index.js';
import * as Custom from './custom/index.js';
import { on, off } from '@/utils/util.js';

export default {
    //网格布局
    name: 'VoGridster',
    components: {
        'VoGridSvg': Grid.Svg,
        'VoGridRect': Grid.Rect,
        'VoGridCircle': Grid.Circle,
        'VoGridText': Grid.Text,
        'VoGridUse': Grid.Use,
        'VoGridStop': Custom.Stop,
        'VoMoveBar': Custom.MoveBar
    },
    props: {
        //单格的最小宽度
        gridMinWidth: {
            type: Number,
            default: 60,
        },
        //单格的最大宽度
        gridMaxWidth: {
            type: Number,
            default: 100,
        },
        //行
        row: {
            type: Number,
            default: 0
        },
        //列
        col: {
            type: Number,
            default: 0
        },
        //边（顶部和左侧序号）的宽度
        barWidth: {
            type: Number,
            default: 40
        },
        //是否开启点击选中
        singleSelect: Boolean,
        //是否开启点击+ctrl键选中
        singleCtrlSelect: Boolean,
        //是否开启鼠标拖动选中
        multipleSelect: Boolean,
        //禁止选中项
        disabled: {
            type: Array,
            default: () => []
        },
        //是否拖拽(开启后选中无效，且鼠标拖动选中会有问题)
        gridDrag: Boolean,
    },
    data() {
        return {
            selectIng: false,//判断是否正在被拉取选中格子中
            ctrlIng: false,//监听是否按下了 ctrl 键
            activeGrids: [],//当前选中的格子 数组
            downGrid: {//记录鼠标 点下 时的位置 x和y
                x: 0,
                y: 0
            },
            movening: false,
            moveGrid: null,
            moveInGrid: null
        }
    },
    computed: {
        svgWidth() {
            let offsetWidth = this.gridMaxWidth * this.col;
            if(this.$el) offsetWidth = this.$el.offsetWidth - this.barWidth;
            const max = Math.max(this.gridMinWidth * this.col, offsetWidth)
            const min = this.gridMaxWidth * this.col
            return min < max ? min : max
        },
        svgHeight() {
            return this.col ? this.svgWidth * this.row / this.col : 0
        },
        gridWidth() {
            return this.col ? Math.floor(this.svgWidth / this.col) : 0
        },
        gridHeight() {
            return this.col ? Math.floor(this.svgWidth / this.col) : 0
        }
    },
    methods: {
        getMousePosition() {
            let x = 0, y = 0;
            let e = window.event;  //标准化事件对象
            if (e.pageX || e.pageY) {  //获取鼠标指针的当前坐标值
                x = e.pageX;
                y = e.pageY;
            } else if (e.clientX || e.clientY) {
                x = e.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
                y = e.clientY + document.documentElement.scrollTop + document.body.scrollTop;
            }
            return {x, y}
        },
        isActive(x, y) {
            return this.activeGrids.findIndex(e => e.x === x && e.y === y) !== -1
        },
        isDisabled(x, y) {
            return this.disabled.findIndex(e => e.x === x && e.y === y) !== -1
        },
        gridsterMousedown(el) {
            if(!this.multipleSelect) return;
            this.selectIng = true;
        },
        gridsterMouseup(el) {
            this.selectIng = false;
            this.movening = false;
            this.moveGrid = null;
            this.$refs.grid.forEach(v => {
                if(v.movening) {
                    v.resetMove()
                }
            })
        },
        gridsterMouseleave(el) {
            // this.selectIng = false;
        },
        gridsterMousemove(el) {
            if(this.movening) {
                if(this.downPosition) {
                    const grid = this.$refs.grid.find(v => v.x === this.moveGrid.x && v.y === this.moveGrid.y)
                    const d = this.getMousePosition();
                    if(grid) {
                        grid.setMove({
                            moveX: d.x - this.downPosition.x,
                            moveY: d.y - this.downPosition.y
                        })
                    }
                }
                //计算鼠标位置所在的网格
                const x = Math.floor(el.offsetX / this.gridWidth);
                const y = Math.floor(el.offsetY / this.gridHeight);
                if(this.moveGrid) {
                    if(this.moveInGrid) {
                        if(this.moveInGrid.x != x || this.moveInGrid.y != y) {
                            this.moveInGrid = {x, y}
                            // console.log(this.moveInGrid.x, this.moveInGrid.y);
                        }
                    } else {
                        this.moveInGrid = {x, y}
                        // console.log(this.moveInGrid.x, this.moveInGrid.y);
                    }
                }
            }
        },
        svgSelect({x, y}) {
            if(this.selectIng) return;

            if(this.ctrlIng) {
                if(!this.singleCtrlSelect) return;
                const index = this.activeGrids.findIndex(e => e.x === x && e.y === y)
                if(index !== -1) {
                    this.activeGrids.splice(index, 1)
                } else {
                    this.activeGrids.push({x, y})
                }
            } else {
                if(!this.singleSelect) return;
                this.activeGrids = [{x, y}];
            }
        },
        svgMousedown({x, y}) {
            this.downGrid = {x, y};
        },
        svgUpOver({x, y}) {
            let arrX = [], arrY = [];
            if(x <= this.downGrid.x) {
                for (let index = this.downGrid.x; index >= x; index--) {
                    arrX.push(index)
                }
            } else if(x > this.downGrid.x) {
                for (let index = this.downGrid.x; index <= x; index++) {
                    arrX.push(index)
                }
            }
            if(y <= this.downGrid.y) {
                for (let index = this.downGrid.y; index >= y; index--) {
                    arrY.push(index)
                }
            } else if(y > this.downGrid.y) {
                for (let index = this.downGrid.y; index <= y; index++) {
                    arrY.push(index)
                }
            }
            const arr = arrX.map(c => {
                return arrY.map(r => ({x: c, y: r}))
            }).flat().filter(e => {
                //过滤禁用的项
                if(this.disabled.findIndex(v => v.x === e.x && v.y === e.y) === -1) {
                    return e
                }
            })
            this.activeGrids = arr;
        },
        svgUpDrag({x, y, movening, el}) {
            this.movening = movening
            if(movening) {
                this.moveGrid = {x, y};
                this.moveInGrid = null;

                this.downPosition = this.getMousePosition()
            } else {
                if(this.moveGrid && this.moveInGrid && (this.moveGrid.x != this.moveInGrid.x || this.moveGrid.y != this.moveInGrid.y)) {
                    this.$emit('move-change', JSON.parse(JSON.stringify(this.moveInGrid)))
                    this.$message.success(`移动到：${this.moveInGrid.x}, ${this.moveInGrid.y}`)
                }
            }
        },
        listenCtrl() {
            on(document, 'keydown', this.ctrlDown)
            on(document, 'keyup', this.ctrlUp)
        },
        ctrlDown(el) {
            if(el.keyCode === 17) {
                this.ctrlIng = true;
            }
        },
        ctrlUp(el) {
            if(el.keyCode === 17) {
                this.ctrlIng = false;
            }
        },
        offCtrl() {
            off(document, 'keydown', this.ctrlDown)
            off(document, 'keyup', this.ctrlUp)
        }
    },
    created() {
        this.listenCtrl()
    },
    beforeDestroy() {
        this.offCtrl()
    },
}
</script>

<style scoped lang="scss">
.gridster{
    .gridster-top_head{
        white-space: nowrap;
    }
    .gridster-row{
        white-space: nowrap;
    }
}
</style>